﻿using System.ComponentModel;
using AnyTap.Models;
using AnyTap.Services;
using CommunityToolkit.Maui.Alerts;
namespace AnyTap;

public partial class App : Application, IScheduler
{
	#region 定义
	/// <summary>
	/// 当前档案
	/// </summary>
	private Doc doc;

	/// <summary>
	/// 控制暂停任务
	/// </summary>
	private static readonly ManualResetEvent manualReset = new(true);

	/// <summary>
	/// 后台任务
	/// </summary>
	private readonly BackgroundWorker commTask = new() { WorkerReportsProgress = true };

	#region IScheduler接口实现
	public StateModel State { get; private set; } = new StateModel();
	public event Action StateChanged;
	public event Action<int> ItemUpdated;
	public event Action<SignalStruct> SignalUpdated;
	#endregion
	#endregion

	public App()
	{
		InitializeComponent();

		MainPage = new AppShell();
		commTask.DoWork += CommTask_DoWork;
		commTask.ProgressChanged += (s, e) => Helper.ShowToast($"循环 {e.ProgressPercentage} / {doc.CycleCount} 次");
		commTask.RunWorkerCompleted += (s, e) => SetFinish(e.Error); //通知测试结束
	}

	protected override void OnSleep()
	{
		base.OnSleep();
		Helper.SaveDocFile();
		Toast.Make("脚本已自动保存").Show();
	}

	#region 任务
	/// <summary>
	/// 后台主任务
	/// </summary>
	private void CommTask_DoWork(object sender, DoWorkEventArgs e)
	{
		if(doc is null || doc.Items.Count <= 0)
			return;

		doc.Reset();
		MainThread.InvokeOnMainThreadAsync(() => ItemUpdated?.Invoke(-1)).Wait(); //通知初始化所有测试项
		for(int i = 0; i < doc.CycleCount; i++)
		{
			commTask.ReportProgress(i);
			foreach(var arg in doc.Items)
			{
				if(!arg.IsEnable)
					continue;

				for(int j = 0; j < arg.Cycle; j++)
				{
					Wait(arg.Delay);
					if(!TapAccessibilityService.Gesture(arg))
					{
						throw new CommException("服务未开启");
					}
				}
			}

			Wait(doc.CycleInterval);
		}
		doc.Finish();
	}

	private void Wait(int tick)
	{
		var tickCycle = Environment.TickCount;
		while(true)
		{
			if(State.Stage != Stage.Running)
				throw new CommException("停止");

			manualReset.WaitOne();
			if(Environment.TickCount - tickCycle >= tick)
				break;

			Thread.Sleep(100);
		}
	}
	#endregion

	#region 状态控制
	void IState.Stop()
	{
		manualReset.Set();
		if(commTask.IsBusy)
		{
			State.Info = StateInfo.Stop; //测试中停止时,仅更新状态,不发出通知. 线程退出后再通知,防止停止时序错乱.
		}
		else
		{
			SetState(StateInfo.Ready);
		}
	}

	bool IState.Pause(bool pause) => pause ? manualReset.Reset() : manualReset.Set();

	void IState.Start() => Start(Helper.Doc);

	public void Start(Doc doc)
	{
		if(commTask.IsBusy)
			return;

		this.doc = doc;
		SetState(StateInfo.Running);
	}

	void IState.Logout() => SetState(StateInfo.Init);

	void IState.SetSignal(SignalStruct input)
	{
		SignalUpdated?.Invoke(input);
	}

	//设置系统为测试结束态
	private async void SetFinish(Exception e)
	{
		if(e is null)
		{
			SetState(StateInfo.Ready);
			await Snackbar.Make($"已完成 {DateTime.Now: HH:mm:ss}", duration: TimeSpan.MaxValue).Show();
		}
		else
		{
			if(e is CommException x)
			{
				await Toast.Make(x.Message).Show();
			}
			else
			{
				Serilog.Log.Information($"State.Fault:{e}");
				await Shell.Current?.DisplayAlert("Fault", e.ToString(), "OK");
			}
			SetState(StateInfo.Fault, e.ToString());
		}
	}

	private void SetState(StateInfo info, string msg = null)
	{
		if(State.Info == info)
			return;

		State.Info = info;
		State.Message = msg;
		StateChanged?.Invoke();
		if(info == StateInfo.Running)
		{
			commTask.RunWorkerAsync();
		}
	}
	#endregion
}

public class CommException(string message) : Exception(message)
{ }
